package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.heima.aliyun.GreenImageScan;
import com.heima.aliyun.GreenTextScan;
import com.heima.common.exception.CustException;
import com.heima.feigns.AdminFeign;
import com.heima.model.common.constants.message.PublishArticleConstants;
import com.heima.model.common.constants.wemedia.WemediaConstants;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.utils.common.SensitiveWordUtil;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.service.WmNewsAutoScanService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author asus
 */
@Service
@Slf4j
public class WmNewsAutoScanServiceImpl implements WmNewsAutoScanService {

    @Autowired
    private WmNewsMapper wmNewsMapper;

    @Value("${file.oss.web-site}")
    String webSite;

    @Autowired
    RabbitTemplate rabbitTemplate;

    @Override
    public void autoScanWmNews(Integer wmNewsId) {
        //1. 根据文章id 远程调用feign查询文章
        if (wmNewsId == null) {
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        WmNews wmNews = wmNewsMapper.selectById(wmNewsId);
        if (wmNews == null) {
            log.error("自动审核文章失败    未查询自媒体文章信息  wmNewsId:{}", wmNewsId);
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        // 2. 判断文章状态是否为待审核状态
        if (wmNews.getStatus().shortValue() == (WemediaConstants.WM_NEWS_UP)) {
            // 抽取出文章中 所有的文本内容 和 所有的图片url集合
            // Map<String,Object>  content 内容   images List<String>
            Map<String, Object> contentAndImageResult = handleTextAndImages(wmNews);

            // 3.1  敏感词审核    失败   修改文章状态(2)

            boolean isSensivice = handleSensitive((String) contentAndImageResult.get("content"), wmNews);
            if (!isSensivice) {return;}
            // 3.2  阿里云的文本审核   失败  状态2  不确定 状态3
            boolean isTextScan = handleTextScan((String) contentAndImageResult.get("content"), wmNews);

            // 3.3  阿里云的图片审核   失败  状态2  不确定 状态3
            List<String> images = (List<String>) contentAndImageResult.get("images");
            if (images != null) {
                boolean isImageScan = handleImageScan(images, wmNews);
                if (!isImageScan) {return;}
                log.info(" 阿里云图片审核通过  =======   ");
            }
            // 4. 判断文章发布时间是否大于当前时间   状态 8
            updateWmNews(wmNews,WmNews.Status.SUCCESS.getCode(),"审核成功");
            //5. 通知定时发布文章
            // 发布时间
            long publishTime = wmNews.getPublishTime().getTime();
            // 当前时间
            long nowTime = new Date().getTime();
            long remainTime = publishTime-nowTime;
            // 发布文章
            rabbitTemplate.convertAndSend(PublishArticleConstants.DELAY_DIRECT_EXCHANGE,
                    PublishArticleConstants.PUBLISH_ARTICLE_ROUTE_KEY,
                    wmNews.getId(),
                    (message ->{
                        // 延时消息 设置
                        message.getMessageProperties().setHeader("x-delay",remainTime<=0?0:remainTime);
                        return message;
                    })
            );
            log.info("立即发布文章通知成功发送，文章id : {}", wmNews.getId());
        }
    }

    @Autowired
    GreenTextScan greenTextScan;

    /**
     * 阿里云文本
     *
     * @param content block: 状态2    review: 状态3    异常: 状态3
     * @param wmNews
     * @return
     */
    private boolean handleTextScan(String content, WmNews wmNews) {
        boolean flag = true;
        try {
            Map map = greenTextScan.greenTextScan(content);
            String suggestion = (String) map.get("suggestion");
            switch (suggestion) {
                case "block":
                    updateWmNews(wmNews, WmNews.Status.FAIL.getCode(), "文本中有违规内容，审核失败");
                    flag = false;
                    break;
                case "review":
                    updateWmNews(wmNews, WmNews.Status.ADMIN_AUTH.getCode(), "文本中有不确定内容，转为人工审核");
                    flag = false;
                    break;
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("阿里云文本审核出现异常 , 原因:{}", e.getMessage());
            updateWmNews(wmNews, WmNews.Status.ADMIN_AUTH.getCode(), "阿里云内容服务异常，转为人工审核");
            flag = false;
        }
        return flag;
    }

    @Autowired
    private GreenImageScan greenImageScan;

    /**
     * 调用阿里云图片监测接口
     *
     * @param images
     * @param wmNews
     * @return
     */
    private boolean handleImageScan(List<String> images, WmNews wmNews) {
        boolean flag = true;
        try {
            Map map = greenImageScan.imageUrlScan(images);
            String suggestion = (String) map.get("suggestion");
            switch (suggestion) {
                case "block":
                    updateWmNews(wmNews, WmNews.Status.FAIL.getCode(), "图有违规");
                    flag = false;
                    break;
                case "review":
                    updateWmNews(wmNews, WmNews.Status.ADMIN_AUTH.getCode(), "图片有不确定内容,转人工审核");
                    flag = false;
                    break;
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("阿里云图片审核出现异常 , 原因:{}", e.getMessage());
            updateWmNews(wmNews, WmNews.Status.ADMIN_AUTH.getCode(), "阿里云内容服务异常，转为人工审核");
            flag = false;
        }
        return flag;
    }

    @Autowired
    AdminFeign adminFeign;

    /**
     * 文章屏蔽关键字
     *
     * @param content
     * @param wmNews
     * @return
     */
    private boolean handleSensitive(String content, WmNews wmNews) {
        // 远程调用获取屏蔽词数据
        ResponseResult<List<String>> result = adminFeign.sensitives();
        // 获取状态码 是否正确
        if (result.getCode().intValue() != 0) {
            CustException.cust(AppHttpCodeEnum.REMOTE_SERVER_ERROR, result.getErrorMessage());
        }

        List<String> list = result.getData();
        // 初始化DFA过滤算法
        SensitiveWordUtil.initMap(list);
        // 3. 检测敏感词
        Map<String, Integer> resultMap = SensitiveWordUtil.matchWords(content);
        if (resultMap != null && resultMap.size() > 0) {
            // 将文章状态改为2
            updateWmNews(wmNews, WmNews.Status.FAIL.getCode(), "内容中包含敏感词: " + resultMap);
            return false;
        }
        return true;
    }


    /**
     * 修改文章状态
     *
     * @param wmNews
     * @param status
     * @param reason
     */
    private void updateWmNews(WmNews wmNews, short status, String reason) {
        // 设置状态
        wmNews.setStatus(status);
        // 设置拒绝的理由
        wmNews.setReason(reason);
        wmNewsMapper.updateById(wmNews);
    }


    /**
     * 抽取 文章中所有 文本内容  及 所有图片路径
     *
     * @param wmNews content  type:text     title
     * @return
     */
    private Map<String, Object> handleTextAndImages(WmNews wmNews) {
        String content = wmNews.getContent();  //[{},{},{}]
        if (StringUtils.isBlank(content)) {
            log.error("自动审核文章失败    文章内容为空");
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID, "文章内容为空");
        }
        List<Map> maps = JSON.parseArray(content, Map.class);
        // 1. 抽取文章中所有文本     家乡很美   _hmtt_   国家伟大
        String contentText = maps.stream()
                // 过滤 出text文本
                .filter(m -> "text".equals(m.get("type")))
                // 获取文本的value
                .map(m -> (String) m.get("value"))
                // 封装为string 使用hmtt连接
                .collect(Collectors.joining("_hmtt_"));
        // 将标题翻入
        contentText = contentText + "_hmtt_" + wmNews.getTitle();

        // 2. 抽取文章中所有图片   content :  全路径       images :  文件名称  + 访问前缀
        List<String> images = maps.stream()
                // 获取type
                .filter(m -> "imges".equals(m.get("type")))
                // 过滤获取所有图片路径
                .map(m -> (String) m.get("value"))
                // 封装为list
                .collect(Collectors.toList());
        if (StringUtils.isNotBlank(wmNews.getImages())) {
            // 按照 逗号 切割封面字符串  得到数组   基于数组得到stream   将每一条数据都拼接一个前缀 收集成集合
            List<String> urls = Arrays.stream(wmNews.getImages().split(","))
                    // 数据拼接一个前缀
                    .map(url -> webSite + url)
                    // 收集list集合
                    .collect(Collectors.toList());
            // 将封面存入images图片对象中
            images.addAll(urls);
        }
        // 去重
        images = images.stream().distinct().collect(Collectors.toList());
        // 封装map数据传给前端
        Map result = new HashMap<>();
        // 添加用户
        result.put("images", images);
        result.put("content", contentText);
        return result;
    }
}
